package dviz.visualSystem.impl;

import java.awt.Canvas;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import com.gibbon.jme.context.JmeContext;
import com.gibbon.jme.context.RenderPass;
import com.jme.input.action.InputAction;
import com.jme.input.action.InputActionEvent;
import com.jme.light.DirectionalLight;
import com.jme.math.Vector3f;
import com.jme.renderer.Camera;
import com.jme.renderer.ColorRGBA;
import com.jme.renderer.Renderer;
import com.jme.scene.Node;
import com.jme.scene.Spatial;
import com.jme.scene.state.LightState;
import com.jme.scene.state.ZBufferState;
import com.jme.system.DisplaySystem;
import com.jme.util.NanoTimer;
import com.jme.util.Timer;

import dviz.tools.ModelRepository;

/*
 * Initialize and configuring JMonkeyEngine Render Passes and gives out an Canvas instance that can be put into a Window. 
 * It takes in an AnimationSystemImpl and renders the containting Node Object.
 */
/**
 * @author zxq071000
 */
public class AnimationSceneSystem {

	/**
	 * @author zxq071000
	 */
	class SimulationRenderPass extends RenderPass {
		boolean asChanged;
		/**
		 * @uml.property  name="aspectRatio"
		 */
		float aspectRatio;
		/**
		 * @uml.property  name="keyAdapter"
		 * @uml.associationEnd  
		 */
		KeyInputAdapter keyAdapter;
		/**
		 * @uml.property  name="mouseAdapter"
		 * @uml.associationEnd  
		 */
		MouseInputAdapter mouseAdapter;
		Node root;
		Timer timer;
		float tpf;

		public SimulationRenderPass() {
			aspectRatio = 640f / 480f;
			timer = new NanoTimer();
			mouseAdapter = new MouseInputAdapter(new InputAction() {
				public void performAction(InputActionEvent evt) {
				}
			});
			keyAdapter = new KeyInputAdapter(new InputAction() {
				public void performAction(InputActionEvent evt) {
				}
			});
		}

		@Override
		protected void doRender(JmeContext context) {
			DisplaySystem display = DisplaySystem.getDisplaySystem();
			Renderer renderer = display.getRenderer();
			renderer.clearColorBuffer();
			renderer.clearZBuffer();

			for (Node n : animationSystemImpl.getBackGroundNode()) {
				renderer.draw(n);
			}
			renderer.draw(root);
			renderer.renderQueue();

			// if (renderer.isInOrthoMode()) {
			// } else {
			// renderer.setOrtho();
			// renderer.unsetOrtho();
			// }
			// if (!simulationPaused)
			canvasInstance.repaint();
		}

		int N = 1;
		int K = 0;

		// long lastTime = System.currentTimeMillis();
		@Override
		protected void doUpdate(JmeContext context) {
			// TODO Auto-generated method stub
			timer.update();
			tpf = timer.getTimePerFrame();
			//				
			// System.out.println("Real:"+(float)(System.currentTimeMillis()-lastTime)/1000f);
			// lastTime = System.currentTimeMillis();
			// System.out.println("Timer:"+tpf);

			try {
				mouseAdapter.update();
				keyAdapter.update();
				if (asChanged) {
					updateCameraConfig();
				}

				// if (!simulationPaused) {
				if ((K++) % N == 0)
					animationSystemImpl.update();
				// }
				if (cameraControl != null)
					cameraControl.updateCamera(tpf, context.getRenderer()
							.getCamera());

				// Update the location of the background objects to make it move
				// with eye position
				for (Node n : animationSystemImpl.getBackGroundNode()) {
					n.setLocalTranslation(context.getRenderer().getCamera()
							.getLocation());
					n.updateRenderState();
					n.updateGeometricState(0, true);
					n.updateModelBound();
				}

			} catch (Exception e) {
				e.printStackTrace();
				System.exit(0);
			}

			root.updateModelBound();
			root.updateWorldBound();
		}

		/**
		 * @return
		 * @uml.property name="aspectRatio"
		 */
		public float getAspectRatio() {
			return aspectRatio;
		}

		/**
		 * @return
		 * @uml.property name="keyAdapter"
		 */
		public KeyInputAdapter getKeyAdapter() {
			return keyAdapter;
		}

		/**
		 * @return
		 * @uml.property name="mouseAdapter"
		 */
		public MouseInputAdapter getMouseAdapter() {
			return mouseAdapter;
		}

		@Override
		public void initPass(JmeContext context) {
			modelRepository.stow();

			Camera camera = context.getRenderer().createCamera(640, 480);
			camera.setParallelProjection(false);
			camera.setFrustumPerspective(45, aspectRatio, 1, 1e5f);
			camera.setLocation(new Vector3f(0, 800, 0));
			camera.lookAt(new Vector3f(), new Vector3f(0, 0, -1));
			camera.update();

			context.getRenderer().setCamera(camera);
			context.getRenderer().setBackgroundColor(ColorRGBA.white);

			// Should be placed somewhere else , or seperated from visualization
			// class. We would want to manage environemnt loading and stuff from
			// else where.
			// root = new Node("root");
			// {
			// Node node = null;
			// node = (Node) modelRepository.getRepository().get("env");
			// SharedNode sn = new SharedNode(node);
			// root.attachChild(sn);
			// }

			root = animationSystemImpl.getSystemRootNode();
			// root.attachChild(agentNode);

			LightState lightState = context.getRenderer().createLightState();
			DirectionalLight directionalLight = new DirectionalLight();
			directionalLight.setDiffuse(new ColorRGBA(1f, 1f, 1f, 1));
			directionalLight.setDirection(new Vector3f(-0.577f, -0.577f,
					-0.577f));
			directionalLight.setAmbient(new ColorRGBA(0.7f, 0.7f, 0.7f, 1));
			directionalLight.setEnabled(true);
			directionalLight.setShadowCaster(true);
			lightState.attach(directionalLight);
			lightState.setEnabled(true);
			root.setRenderState(lightState);

			ZBufferState bufferState = context.getRenderer()
					.createZBufferState();
			bufferState.setEnabled(true);
			bufferState.setFunction(ZBufferState.TestFunction.LessThan);

			Spatial sphere = (Spatial) ModelRepository.get().getRepository()
					.get("town");
			// sphere.clearRenderState(RenderState.RS_MATERIAL);
			// sphere.clearRenderState(RenderState.RS_TEXTURE);
			// root.setCullHint(CullHint.Never);
			root.attachChild(sphere);

			root.setRenderState(bufferState);

			// root.setTextureCombineMode(TextureCombineMode.Off);
			// root.setLightCombineMode(LightCombineMode.Off);

			root.updateRenderState();
			root.updateModelBound();
			canvasInstance.repaint();

		}

		public void resizeCanvas(int w, int h) {
			setAspectRatio((float) w / (float) h);
		}

		/**
		 * @param aspectRatio
		 * @uml.property name="aspectRatio"
		 */
		public void setAspectRatio(float aspectRatio) {
			this.aspectRatio = aspectRatio;
			asChanged = true;
		}

		private void updateCameraConfig() {
			Camera camera = JmeContext.get().getRenderer().getCamera();
			camera.setParallelProjection(false);
			camera.setFrustumPerspective(45, aspectRatio, 1, 1e5f);
			camera.update();
			asChanged = false;
			canvasInstance.repaint();
		}
	}

	public static final int CM_CHASE_CHR = 1;
	public static final int CM_WHOLEVIEW = 0;

	public static void main(String s[]) {

	}

	/**
	 * @uml.property  name="animationSystemImpl"
	 * @uml.associationEnd  
	 */
	AnimationSystemImpl animationSystemImpl;
	/**
	 * @uml.property  name="cameraControl"
	 * @uml.associationEnd  
	 */
	CameraControl cameraControl;
	public Canvas canvasInstance;
	// boolean initApplication;
	/**
	 * @uml.property  name="modelRepository"
	 * @uml.associationEnd  
	 */
	ModelRepository modelRepository;

	/**
	 * @uml.property  name="myRenderPass"
	 * @uml.associationEnd  
	 */
	SimulationRenderPass myRenderPass;

	// HashMap<String, String> properties;
	// RvoSetupInfo setupInfo;

	// AgentViewModel simulationAdapter;

	// boolean simulationPaused;

	public AnimationSceneSystem(ModelRepository modelRepository,
			AnimationSystemImpl animationSystemImpl) {
		// this.properties = prop;
		this.modelRepository = modelRepository;
		this.animationSystemImpl = animationSystemImpl;
		// simulationAdapter = new AgentViewModel(agentSystem);
		// simulationPaused = true;
	}

	/**
	 * @return
	 * @uml.property name="cameraControl"
	 */
	public CameraControl getCameraControl() {
		return cameraControl;
	}

	// public boolean isSimulationPaused() {
	// return simulationPaused;
	// }

	// //TODO: reroute reinitialize command to corresponding adapter
	// public void restartSimulation() {
	// simulationAdapter.restart();
	// }

	/**
	 * @param cameraControl
	 * @uml.property name="cameraControl"
	 */
	public void setCameraControl(CameraControl cameraControl) {
		this.cameraControl = cameraControl;
	}

	public void setCanvas(JmeContext context) {
		Canvas canvas = context.getCanvas();
		canvasInstance = canvas;
		if (myRenderPass == null)
			myRenderPass = new SimulationRenderPass();
		context.getPassManager().add(myRenderPass);

		canvasInstance.addComponentListener(new ComponentAdapter() {
			@Override
			public void componentResized(ComponentEvent ce) {
				myRenderPass.resizeCanvas(canvasInstance.getWidth(),
						canvasInstance.getHeight());
			}
		});
		myRenderPass.getMouseAdapter().setup(canvasInstance);
		canvasInstance.repaint();
	}

	// public void setSimulationPaused(boolean simulationPaused) {
	// this.simulationPaused = simulationPaused;
	// if (!simulationPaused)
	// canvasInstance.repaint();
	// }

	// public void setupScenario(RvoSetupInfo info) {
	// initApplication = true;
	// this.setupInfo = info;
	// }
}
